/*******************************************************************************
* Copyright (C) 2023
* @file      app_init.c
* @author    zhang
* @version   1.0.0.1
* @date      2023/10/26
* @brief     
* details.
* 
* change history
* <date>      | <version>   | <author>      | <description>
* 2023/10/26  | 1.0.0.1     | zhang         | create file
*
*******************************************************************************/
#include "app_includes.h"
#include "comm_apply.h"
#include "common.h"

//static uint8_t txBuff[280];
//static uint16_t txBuffLen;
static app_update_t app_update = {
    .cmd=TOOL_UD_IDLE, .id=2, .frame_len_max=190};

int32_t commApplyResponse(CommApply *comm_apply, uint8_t *data, uint16_t len);

int32_t protocol_decode(CommApply *comm_apply, uint8_t *data, uint16_t len)
{
    uint16_t crc;
    if(len<6)
        return -1;
    if(data[0]!=0x55 || data[1]!=data[2] || data[3]!=0x55 || data[len-1]!=0xAA || data[1]!=len-6)
        return -2;
    if(check8BitSum(&data[4],data[1])!=data[len-2])
        return -3;
    commApplyResponse(comm_apply, data+4, data[1]);
    return 0;
}

void protocol_send(CommApply *comm_apply, uint8_t *data, uint16_t len)
{
    uint16_t crc;
    comm_apply->tx_buff[0] = 0x55;
    comm_apply->tx_buff[1] = len;
    comm_apply->tx_buff[2] = len;
    comm_apply->tx_buff[3] = 0x55;
    //应用数据已经写入
    
    comm_apply->tx_buff[4+len] = check8BitSum(data, len);
    comm_apply->tx_buff[5+len] = 0xaa;
    comm_apply->tx_buff_len = len+6;
    
    comm_apply->send(comm_apply->tx_buff, comm_apply->tx_buff_len);
    //board_uart_send(0, comm_apply->tx_buff, comm_apply->tx_buff_len);
    //board_serial_send(BoardSerialDebugID, comm_apply->tx_buff, comm_apply->tx_buff_len);
    ////uartWrite(&uartPC, txBuff, txBuffLen, -1, -1);
}

void commApplyInit(CommApply *comm_apply, uint8_t *tx_buff)
{
    comm_apply->dataSendLenMax = 240;
    comm_apply->tx_buff = tx_buff;
    comm_apply->buff = &tx_buff[4];
}

void commApplysend(CommApply *comm_apply, uint8_t cmd)
{
    int len_hasSend = 0;
    int dataSendLen = comm_apply->tx_dataLen;
    uint8_t offset = 2;
    
    comm_apply->header.cmd.cmd = cmd;
    comm_apply->header.cmd.master = 0;
    
    if(comm_apply->header.cmd.err) //错误帧
        comm_apply->tx_dataLen = 0;
    
    comm_apply->header.totalPage = (comm_apply->tx_dataLen+comm_apply->dataSendLenMax-1)/comm_apply->dataSendLenMax;
    
    if(comm_apply->header.totalPage>1) //是多页数据，重新计算要发送长度
    {
        comm_apply->header.cmd.muti_page = 1;
        offset = 4;
        len_hasSend = (comm_apply->header.currentPage-1) * comm_apply->dataSendLenMax;
        dataSendLen = comm_apply->tx_dataLen - len_hasSend;
        if(dataSendLen>comm_apply->dataSendLenMax)
            dataSendLen = comm_apply->dataSendLenMax;
    }
    
    memcpy(comm_apply->buff,&comm_apply->header, sizeof(ApplyDataHeader));
    memcpy(comm_apply->buff+offset,comm_apply->data+len_hasSend, dataSendLen);
    protocol_send(comm_apply, comm_apply->buff, offset+dataSendLen);
}

/*
 * <ApplyDevInfoCrc> 读取资源crc
 *  
*/
uint8_t commApplyReadInfo(CommApply *comm_apply)
{
    switch(comm_apply->header.id)
    {
    case ApplyDevInfoCrc:
        memcpy(comm_apply->data, &app_dev.src_package->header.crc, 2);
        memcpy(comm_apply->data+2, &app_dev.para_package->header.crc, 2);
        comm_apply->tx_dataLen = 4;
        return 0;
    
    default:
      
        return 1;
    }
}

uint8_t commApplyWritePara(CommApply *comm_apply)
{
    
    switch(comm_apply->header.id)
    {
    case ApplyParaRun:
        memcpy(&app_dev.para.run, comm_apply->rx_data, sizeof(app_dev.para.run));
        xEventGroupSetBits(sys_event, kSysEvent_ParaChange);
        app_dev.change.para_run = 1;
        app_dev_para_init();
        break;
    case ApplyParaStore:
        memcpy(&app_dev.para.store, comm_apply->rx_data, sizeof(app_dev.para.store));
        xEventGroupSetBits(sys_event, kSysEvent_ParaChange);
        app_dev.change.para_store = 1;
        board_memory_write(DEVICE_STORE_ADDR, (uint8_t *)&app_dev.para.store, sizeof(app_dev.para.store));//保存到EEPROM
        app_dev_para_init();
        break;
    default:
        return 1;
    }
    comm_apply->tx_dataLen = 0;
    return 0;
}

uint8_t commApplyReadPara(CommApply *comm_apply)
{  
    char *p;
    switch(comm_apply->header.id)
    {
    case ApplyParaInfo:
        p = (char *)&app_dev.para.info;
        comm_apply->tx_dataLen = sizeof(app_dev.para.info);
        break;
    case ApplyParaStore:
        p = (char *)&app_dev.para.store;
        comm_apply->tx_dataLen = sizeof(app_dev.para.store);
        break;
    case ApplyParaRun:
        p = (char *)&app_dev.para.run;
        comm_apply->tx_dataLen = sizeof(app_dev.para.run);
        break;
    case ApplyParaStatus:
        p = (char *)&app_dev.para.status;
        comm_apply->tx_dataLen = sizeof(app_dev.para.status);
        break;
    default:
        return 1;
    }
    memcpy(comm_apply->data, p, comm_apply->tx_dataLen);
    comm_apply->header.currentPage = comm_apply->rx_data[0];
    return 0;
}

uint8_t commApplyReadMeter(CommApply *comm_apply)
{
    uint16_t i;
    
    comm_apply->data[0] = app_dev.change.value;
    app_dev.change.value = 0;
    if(comm_apply->header.id==0) { //读取所有
        for(i=0;i!=SRC_TABLE_METER_ITEM_NUM;i++) {
            comm_apply->data[i*5+1] = !app_dev.meter.group[i].invalid;
            memcpy(comm_apply->data+2+i*5, (void *)&app_dev.meter.group[i].value, 4);
        }
        comm_apply->tx_dataLen = SRC_TABLE_METER_ITEM_NUM*5+1;
    }
    else {
        comm_apply->data[0] = !app_dev.meter.group[comm_apply->header.id-1].invalid;
        memcpy(comm_apply->data+2, (void *)&app_dev.meter.group[comm_apply->header.id-1].value, 4);
        comm_apply->tx_dataLen = 5;
    }
    comm_apply->tx_dataLen += 1; //bug，不然vcp发不出去
    
    return 0;
}

uint8_t commApplyReadSignal(CommApply *comm_apply)
{
    comm_apply->tx_dataLen = 0;
    return 0;
}

/*adc | adc2 | */
uint8_t commApplyReadSample(CommApply *comm_apply)
{
    uint16_t i;
    if(comm_apply->header.id==0) { //读取所有adc
        for(i=0;i!=SRC_TABLE_METER_ITEM_NUM;i++) {
            memcpy(comm_apply->data+i*4, &app_dev.meter.group[i].adc, 4);
        }
        comm_apply->tx_dataLen = 4*SRC_TABLE_METER_ITEM_NUM;
    }
    else {
        memcpy(comm_apply->data, &app_dev.meter.group[comm_apply->header.id-1].adc, 4);
        comm_apply->tx_dataLen = 4;
    }
    return 0;
}

uint8_t commApplyReadMap(CommApply *comm_apply)
{
    uint16_t offset = 0, num = DEVICE_FACTOR_MAP_NUM;
    if(comm_apply->header.id!=0) {
        offset = app_dev.meter.group[comm_apply->header.id-1].map_offset;
        num = app_dev.src_package->item[comm_apply->header.id-1].attr.meter.map_num;
    }
    comm_apply->tx_dataLen = num*sizeof(map_para_t);
    memcpy(comm_apply->data, (void *)&app_dev.factor.map[offset], comm_apply->tx_dataLen);
    return 0;
}

uint8_t commApplyWriteMap(CommApply *comm_apply)
{
    uint16_t offset = 0, num = DEVICE_FACTOR_MAP_NUM;
    if(comm_apply->header.id!=0) {
        offset = app_dev.meter.group[comm_apply->header.id-1].map_offset;
        num = app_dev.src_package->item[comm_apply->header.id-1].attr.meter.map_num;
    }    
    taskENTER_CRITICAL();//关中断
    memcpy((void *)&app_dev.factor.map[offset], comm_apply->rx_data, num*sizeof(map_para_t));
    taskEXIT_CRITICAL();//开中断
    board_memory_write(DEVICE_FACTOR_ADDR, (uint8_t *)&app_dev.factor, sizeof(app_dev.factor));
    comm_apply->tx_dataLen = 0;
    return 0;
}

uint8_t commApplyReadPID(CommApply *comm_apply)
{
    uint16_t offset = 0, num = DEVICE_FACTOR_PID_NUM;
    if(comm_apply->header.id!=0) {
        offset = app_dev.meter.group[comm_apply->header.id-1].pid_offset;
        num = app_dev.src_package->item[comm_apply->header.id-1].attr.meter.ctrl_num;
    }
    comm_apply->tx_dataLen = num*sizeof(pid_para_t);
    comm_apply->tx_dataLen += 1; //bug，不然vcp发不出去
    memcpy(comm_apply->data, (void *)&app_dev.factor.pid[offset], comm_apply->tx_dataLen);
    return 0;
}

uint8_t commApplyWritePID(CommApply *comm_apply)
{    
    uint16_t offset = 0, num = DEVICE_FACTOR_PID_NUM;
    if(comm_apply->header.id!=0) {
        offset = app_dev.meter.group[comm_apply->header.id-1].pid_offset;
        num = app_dev.src_package->item[comm_apply->header.id-1].attr.meter.ctrl_num;
    }
    taskENTER_CRITICAL();//关中断
    memcpy((void *)&app_dev.factor.pid[offset], comm_apply->rx_data, num*sizeof(pid_para_t));
    taskEXIT_CRITICAL();//开中断
    board_memory_write(DEVICE_FACTOR_ADDR, (uint8_t *)&app_dev.factor, sizeof(app_dev.factor));
    comm_apply->tx_dataLen = 0;
    return 0;
}

uint8_t commApplyReadWave(CommApply *comm_apply)
{
    uint16_t interval = 0;
    uint8_t num_send = 0;
    memcpy(&interval, comm_apply->rx_data, 2);
    taskENTER_CRITICAL();//关中断
    if(comm_apply->header.id!=app_dev.wave.id || interval!=app_dev.wave.interval) {
        device_wave_init(comm_apply->header.id, interval);
    }
    else {
        num_send = app_dev.wave.len > 15 ? 15 : app_dev.wave.len;
        device_wave_read(comm_apply->data, num_send);
    }
    taskEXIT_CRITICAL();//开中断
    comm_apply->tx_dataLen = num_send*sizeof(device_wave_data_t);
    return 0;
}

uint8_t commApplyOutTest(CommApply *comm_apply)
{
    uint16_t i;
    uint16_t value;
    uint8_t lock;
    if(comm_apply->header.id==0) {
        for(i=0;i!=SRC_TABLE_OUT_ITEM_NUM;i++) {
            lock = comm_apply->rx_data[3*i];
            memcpy(&value, &comm_apply->rx_data[3*i+1], 2);
            device_pwm_out_test(i, value, lock);
        }
    }
    else {
        lock = comm_apply->rx_data[0];
        memcpy(&value, &comm_apply->rx_data[1], 2);
        device_pwm_out_test(comm_apply->header.id-1, value, lock);
    }
    comm_apply->tx_dataLen = 0;
    return 0;
}


int32_t commApplyResponse(CommApply *comm_apply, uint8_t *data, uint16_t len)
{
    uint8_t err = 0;
    uint8_t recv_complete = 1;
    ApplyDataHeader *recv_header = (ApplyDataHeader *)data;
    
    if(len<2)
        return ApplyResultNoUse;
    /* 接收到的是多页数据 */
    if(recv_header->cmd.muti_page)
    {
        if(recv_header->currentPage==0||recv_header->currentPage>recv_header->totalPage)
            err = 1;//发送错帧回复帧  
        if(recv_header->currentPage>1) //继续上帧数据
            if(recv_header->currentPage!=comm_apply->header.currentPage+1 || 
               recv_header->cmd.function!=comm_apply->header.cmd.function)
                err = 1;//发送错帧回复帧
        if(recv_header->currentPage==1) //第一帧开始接收
            comm_apply->rx_dataLen = 0;
        memcpy(comm_apply->data + comm_apply->rx_dataLen, data + sizeof(ApplyDataHeader), len-sizeof(ApplyDataHeader));
        comm_apply->rx_dataLen += len-sizeof(ApplyDataHeader);
        if(recv_header->currentPage!=recv_header->totalPage) //当前未接收完毕
        {
            //comm_apply->buff
            comm_apply->tx_dataLen = 0;
            recv_complete = 0;
        }
        else
            comm_apply->rx_data = comm_apply->data;
    }
    else
    {
        //recv_header->currentPage = 1;
        comm_apply->rx_data = data + 2;
        comm_apply->rx_dataLen = len - 2;
    }
    /* 要发送的是多页数据，且当前指令匹配，且当前要读的页是下一页 */
    if(comm_apply->header.cmd.muti_page==1 &&
       recv_header->cmd.cmd==comm_apply->header.cmd.cmd && 
       recv_header->currentPage==comm_apply->header.currentPage+1)
    {
        comm_apply->header.currentPage++;
    }
    else if(recv_complete) //接收完毕可处理
    {
        comm_apply->header.id = recv_header->id;
        switch(recv_header->cmd.function)
        {
        case ApplyCmdReadInfo:
            err = commApplyReadInfo(comm_apply);
            break;
        case ApplyCmdReadMeter:
            err = commApplyReadMeter(comm_apply);
            break;
        case ApplyCmdReadSignal:
            err = commApplyReadSignal(comm_apply);
            break;
        case ApplyCmdReadSample:
            err = commApplyReadSample(comm_apply);
            break;
        case ApplyCmdReadMap:
            err = commApplyReadMap(comm_apply);
            break;
        case ApplyCmdWriteMap:
            err = commApplyWriteMap(comm_apply);
            break;
        case ApplyCmdReadPID:
            err = commApplyReadPID(comm_apply);
            break;
        case ApplyCmdWritePID:
            err = commApplyWritePID(comm_apply);
            break;
        case ApplyCmdReadPara:
            err = commApplyReadPara(comm_apply);
            break;
        case ApplyCmdWritePara:
            err = commApplyWritePara(comm_apply);
            break;
        case ApplyCmdReadWave:
            err = commApplyReadWave(comm_apply);
            break;
        case ApplyCmdOutTest:
            err = commApplyOutTest(comm_apply);
            break;
        default:
            err = 1;
            break;
        }
    }

    commApplysend(comm_apply, recv_header->cmd.function|(err<<7));
    return ApplyResultOK;
}